package com.longteng.diamond.service.impl;

import com.google.common.collect.Maps;
import com.longteng.diamond.dao.InterfaceMockDataMapper;
import com.longteng.diamond.dao.InterfaceScriptMapper;
import com.longteng.diamond.domain.InterfaceMock;
import com.longteng.diamond.domain.InterfaceMockData;
import com.longteng.diamond.domain.InterfaceScript;
import com.longteng.diamond.service.MockMatchDataService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.codehaus.groovy.control.MultipleCompilationErrorsException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.servlet.http.HttpServletRequest;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;

/**
 * Created by Administrator
 * DATE : 2018/8/12
 * TIME : 10:25
 * PROJECT : java-lesson
 * PACKAGE : com.longteng.lesson
 *
 * @author <a href="mailto:taki@qq.com">Administrator</a>
 */
@Component
@Slf4j
public class CustomMatchImpl implements MockMatchDataService {
    @Autowired
    InterfaceScriptMapper scriptMapper;
    @Autowired
    InterfaceMockDataMapper dataMapper;

    /**
     * 自定义脚本匹配mock数据
     *
     * @param
     * @return String
     */
    @Override
    public String dataMatch(InterfaceMock interfaceMock, List<InterfaceMockData> interfaceMockDataList, HttpServletRequest httpRequest) {
        InterfaceScript interfaceScript = scriptMapper.getInterfaceScript(interfaceMock.getInterfaceMockId());
        if(null==interfaceScript){
            return "您的mock接口【"+interfaceMock.getInterfaceAliasName()+"】未绑定脚本,请先绑定脚本";
        }
        String body = null;
        try {
            body = IOUtils.toString(httpRequest.getReader());
        } catch (Exception e) {
                log.error("读取requestBody参数异常",e);
        }
        /**获取header存放在headerMap**/
        Enumeration<String> headerNames = httpRequest.getHeaderNames();
        Map<String, String> headerMap = Maps.newHashMap();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            headerMap.put(headerName, httpRequest.getHeader(headerName));
        }
        /**获取入参是值**/
        Map<String, String> paramMap = this.formatMap(httpRequest.getParameterMap());
        /**传入脚本的参数,做成内置变量**/
        Map<String, Object> scriptMap = Maps.newHashMap();
        scriptMap.put("url", interfaceMock.getInterfaceName());
        scriptMap.put("headerMap", headerMap);
        scriptMap.put("interfaceMethod", interfaceMock.getInterfaceMethod());
        scriptMap.put("paramMap", paramMap);
        scriptMap.put("body", body);
        scriptMap.put("httpRequest",httpRequest);
        String script = interfaceScript.getScript();
        script = script.replace("@@", "\"");
        FileWriter writer = null;
        /**定义调试日期,如果开启调试则使用自定义的writer,println输入的内容和异常信息写入日志**/
        if (interfaceScript.isDebug()) {
            try {
                String fileName = interfaceMock.getInterfaceAliasName() + interfaceMock.getInterfaceMockId();
                /**使用接口别名和id创建log文件,true代表追加**/
                writer = new FileWriter(fileName + ".log", true);
            } catch (IOException e) {
                log.error("打开接口调试文件异常", e);
            }
        }
        Object returnValue = null;
        try {
            returnValue = this.runGroovyScript(script, scriptMap, writer);
        } catch (Exception e) {
            log.error("执行自定义脚本异常", e);
            try {
                if(null!=writer) {
                    writer.write(e.toString());
                }
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            return "脚本执行异常,请查看脚本代码是否编写错误,异常信息:"+e.toString();
        } finally {
            try {
                if (null != writer) {
                    writer.flush();
                    writer.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (null == returnValue) {
            return "脚本执行异常";
        }
        InterfaceMockData interfaceMockData = dataMapper.findInterfaceMockDataById((Integer) returnValue);
        if (null != interfaceMockData) {
            return interfaceMockData.getMockData();
        }
        return "未匹配到任何数据";
    }

    /**
     * 执行groovy脚本
     *
     * @param
     * @return String
     */
    public Object runGroovyScript(String script, Map<String, Object> params, Writer writer) throws Exception {
        if (script == null || "".equals(script)) {
            throw new RuntimeException("方法runGroovyScript无法执行，传入的脚本为空");
        }
        /**脚本引擎,可以执行很多脚本:groovy , js 等**/
        ScriptEngineManager factory = new ScriptEngineManager();
        ScriptEngine engine = factory.getEngineByName("groovy");
        /**如果writer不等于null那么使用自定义的writer输出脚本的异常信息和println打印的信息到文件中**/
        if (null != writer) {
            ScriptContext context = engine.getContext();
            context.setWriter(writer);
            context.setErrorWriter(writer);
        }
        /**把入参放到脚本里面**/
        Bindings bindings = engine.createBindings();
        bindings.putAll(params);
        return engine.eval(script, bindings);
    }

    /**
     * 讲http param的参数转换成map
     *
     * @param stringMap
     * @return Map
     */
    private Map formatMap(Map<String, String[]> stringMap) {
        Map<String, String> paramMap = Maps.newHashMap();
        for (String key : stringMap.keySet()) {
            String[] args = stringMap.get(key);
            paramMap.put(key, args[0]);
        }
        return paramMap;
    }
}
